package com.example.webchar.webchar.service.serverimpl;

import java.util.*;

import com.example.webchar.webchar.novelenum.NovelStartEnum;
import com.example.webchar.webchar.mapper.master.ChapterNameMaster;
import com.example.webchar.webchar.mapper.master.NovelContentMaster;
import com.example.webchar.webchar.mapper.master.NovelMaster;
import com.example.webchar.webchar.mapper.slave.NovelSlave;
import com.example.webchar.webchar.pojo.ChapterName;
import com.example.webchar.webchar.pojo.Novel;
import com.example.webchar.webchar.pojo.NovelContent;
import com.example.webchar.webchar.service.CrawlService;
import com.example.webchar.webchar.utils.MailUtils;
import com.example.webchar.webchar.utils.NovelTableName;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import java.io.IOException;

/**
 * @program: webchars
 * @description
 * @author: 毛叶贵子
 * @create: 2021-08-22 02:53
 * 爬虫服务层
 **/
@Slf4j
@Component
public class CrawlImpl implements CrawlService {
    @Autowired
    private NovelSlave novelSlave;
    @Autowired
    private NovelMaster novelMaster;
    @Autowired
    private ChapterNameMaster chapterNameMaster;
    @Autowired
    private NovelContentMaster novelContentMaster;
    @Autowired
    private MailUtils mailUtils;

    private final String HTTP_HEAD = "https://www.bixiabook.com/";
    private String updateLocaltion;
    private Integer id;
    private final String URL = "https://www.duoben.net/s123.php?ie=gbk&q=";
    private final String CHAP_TERN_AME_URL = "https://www.duoben.net";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void novelCrawl(String name, String email) {
        List<Novel> selNovel = novelSlave.selNovelName();
        //在外部查询所有的小说 避免在循环中使用sql查询
        ArrayList<Novel> novels = new ArrayList<>();
        try {
            Document novelCon = Jsoup.connect(HTTP_HEAD + "index.php?s=/web/index/search").data("name", name).post();
            //返回爬取网站的信息
            Elements elementsByTag = novelCon.getElementById("main").getElementsByTag("li");
            //获取母模板
            for (int i = 1; i < elementsByTag.size(); i++) {
                updateLocaltion = null;
                //同名情况下 更新的地址
                id = 0;
                Document chapterCon = Jsoup.connect(HTTP_HEAD + elementsByTag.get(i).getElementsByTag("a").get(0).attr("href")).get();
                //返回小说目录信息
                Novel novel = setBook(selNovel, chapterCon);
                //将小说基础信息封装
                Elements elementsByTag1 = chapterCon.getElementById("list").getElementsByTag("dd");
                //获取目录页的信息
                setNovelList(novels, novel, elementsByTag1);
                //将信息载入到Novels集合
            }
            ArrayList<ChapterName> chapterNames1 = new ArrayList<>();
            setChapterNameList(chapterNames1, novels);
            //删除重复的小说和增加不同的目录
            if (chapterNames1.size() != 0) {
                chapterNameMaster.insChapterList(chapterNames1);
                ArrayList<NovelContent> novelContents = new ArrayList<>();
                setNovelConten(novelContents, chapterNames1);
                //添加上页和下页
                novelContentMaster.insNovelContentList(novelContents);
                sendAnEmail(email, novels);
                //引入发送短信模块
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * name
     * List<Novel> selNovel 查询小说库中的所有小说
     * 根据小说名, 获取小说目录, 小说内容放入实体类中
     */
    public Novel setBook(List<Novel> selNovel, Document chapterCon) {
        Novel novel = new Novel();
        Elements novelElement = chapterCon.getElementsByTag("meta");
        //获取小说详情母版
        novel.setBriefIntroduction(novelElement.get(6).attr("content"))
                //获取小说简介
                .setName(novelElement.get(9).attr("content"))
                //获取小说作者
                .setNovelName(novelElement.get(5).attr("content"))
                //获取小说名称
                .setScore(chapterCon.getElementById("score_content").getElementsByTag("em").get(0).text())
                //获取小说评分
                .setUrl("https://www.bixiabook.com" + novelElement.get(7).attr("content"));
        //获取小说图片地址
        String novelType = novelElement.get(8).attr("content");
        //获取小说类型
        if ((NovelTableName.FAN_TASY).equals(novelType)) {
            novel.setType(NovelStartEnum.FANTASY.ordinal());
        } else if ((NovelTableName.FIXTHE_TRUTH).equals(novelType)) {
            novel.setType(NovelStartEnum.FIXTHETRUTH.ordinal());
        } else if ((NovelTableName.METR_OPOLIS).equals(novelType)) {
            novel.setType(NovelStartEnum.METROPOLIS.ordinal());
        } else if ((NovelTableName.THROUGH).equals(novelType)) {
            novel.setType(NovelStartEnum.THROUGH.ordinal());
        } else if ((NovelTableName.ONLINE).equals(novelType)) {
            novel.setType(NovelStartEnum.ONLINE.ordinal());
        } else if ((NovelTableName.SCIENECFICTION).equals(novelType)) {
            novel.setType(NovelStartEnum.SCIENECFICTION.ordinal());
        } else {
            novel.setType(NovelStartEnum.OTHER.ordinal());
        }
        for (Novel selNovel2 : selNovel) {
            if (selNovel2.getNovelName().equals(novelElement.get(5).attr("content"))) {
                updateLocaltion = selNovel2.getUpdateLocation();
                id = selNovel2.getId();
                novel = selNovel2;
                //如果有相同名字 用有id的代替没有id的
            }
        }
        return novel;
    }

    /**
     * @param novels
     * @param novel
     * @param elementsByTag1
     */
    public void setNovelList(List<Novel> novels, Novel novel, Elements elementsByTag1) {
        int j = elementsByTag1.size() < 12 ? elementsByTag1.size() / 2 : 12;
        //设置爬出章节的开始位置 12是小说超出12章后的倒排章节信息
        String locationDate = null;
        if (updateLocaltion != null && id != 0) {
            for (; j < elementsByTag1.size(); j++) {
                if (updateLocaltion.equals(elementsByTag1.attr("href"))) {
                    break;//循环查询在相同的名称下 有没有相同的页码
                }
            }
        }
        ArrayList<ChapterName> chapterNames = new ArrayList<>();
        for (; j < elementsByTag1.size(); j++) {
            ChapterName chapterName = new ChapterName();
            chapterName.setNovelId(id);
            //放入novel_id
            chapterName.setChapterName(elementsByTag1.get(j).text());
            //获取章节信息
            log.info("小说名称" + novel.getNovelName() + "章节为" + elementsByTag1.get(j).text());
            //给chapetName表数据
            NovelContent novelContent = new NovelContent();
            try {
                Document connect = Jsoup.connect("https://www.bixiabook.com" + elementsByTag1.get(j).getElementsByTag("a").attr("href")).get();
                //获取每章地址
                Element content = connect.getElementById("content");
                //获取文章内容
                content.getElementsByTag("p").remove();
                //删除指定的标签
                content.getElementsByTag("div").remove();
                content.prepend("<p>&nbsp;&nbsp;&nbsp;天才一秒记住本站地址最快更新！无广告！</p></br>");
                novelContent.setContent(content.html());
                //添加小说内容
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                chapterName.setNovelContent(novelContent);
                locationDate = elementsByTag1.get(j).getElementsByTag("a").attr("href");
                chapterNames.add(chapterName);
            }
        }
        novel.setChapterNames(chapterNames);
        novel.setUpdateLocation(locationDate);
        novels.add(novel);
    }

    /**
     * @param chapterNames 增加关联
     * @param novels       将存在的小说
     */
    public void setChapterNameList(List<ChapterName> chapterNames, List<Novel> novels) {
        for (int i = 0; i < novels.size(); i++) {
            if (novels.get(i).getId() != null) {
                for (int j = 0; j < novels.get(i).getChapterNames().size(); j++) {
                    chapterNames.add(novels.get(i).getChapterNames().get(j));
                }
                novels.remove(i);
                //这里不能使用foreach
            }
        }
        if (novels.size() != 0) {
            novelMaster.insNovelList(novels);
            for (Novel novel : novels) {
                for (ChapterName chapterName : novel.getChapterNames()) {
                    chapterName.setNovelId(novel.getId());
                    //将没有id的赋值 放入ChapteName
                    chapterNames.add(chapterName);
                }
            }
        }

    }

    /**
     * @param novelContents 将内容中的上页和下页赋值
     */
    public void setNovelConten(List<NovelContent> novelContents, List<ChapterName> chapterNames1) {
        for (int i = 0; i < chapterNames1.size(); i++) {
            chapterNames1.get(i).getNovelContent().setChapterNameId(chapterNames1.get(i).getId());
            if (i == 0) {
                chapterNames1.get(i).getNovelContent().setUpPage(chapterNames1.get(i).getId()).setNextPage(chapterNames1.get(i + 1).getId());
            } else if (i + 1 >= chapterNames1.size()) {
                chapterNames1.get(i).getNovelContent().setUpPage(chapterNames1.get(i - 1).getId()).setNextPage(chapterNames1.get(i).getId());
            } else {
                chapterNames1.get(i).getNovelContent().setUpPage(chapterNames1.get(i - 1).getId()).setNextPage(chapterNames1.get(i + 1).getId());
            }
            novelContents.add(chapterNames1.get(i).getNovelContent());
        }

    }

    /**
     * @param emial  当前登录账号的qq
     * @param novels 爬取的小说信息
     */

    public void sendAnEmail(String emial, List<Novel> novels) {
        String email = emial.equals(null) ? "1983598699@qq.com" : emial;
        String subgect = "小说上载成功,请阅";
        String text = "您选择获取的小说信息有";
        if (novels.size() != 0) {
            for (Novel novel : novels) {
                text += "<<" + novel.getNovelName() + ">>\n";
            }
        } else {
            text += "为空";
        }
        try {
            mailUtils.sendMail(email, subgect, text);
            //发送信息
        } catch (MessagingException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void novelCrawlChangeTheSource(String name) {
        List<Novel> selNovel = novelSlave.selNovelName();
        //需要在数据库中设立字段(小说来源）
        ArrayList<Novel> novels = new ArrayList<>();
        try {
            List<Novel> novels1 = setBookChangeTheSource(name, selNovel, novels);
            System.out.println(novels1);
        } catch (IOException e) {
            new Exception("err");
        }

    }

    /**
     * @param name     输入名称
     * @param selNovel 获取数据库中的所有小说名称
     * @param novels   集合类
     * @return 返回所有满足当前信息的小说信息
     * @throws IOException
     */

    public List<Novel> setBookChangeTheSource(String name, List<Novel> selNovel, List<Novel> novels) throws
            IOException {
        Document document = Jsoup.connect(URL + name).get();
        Elements elementsByTag = document.getElementsByClass("bookbox");
        //根据网站的class信息获取内容
        for (Element element : elementsByTag) {
            Elements elementsByTag1 = element.getElementsByTag("a");
            Document chapterNameDocument = Jsoup.connect(CHAP_TERN_AME_URL + elementsByTag1.attr("href")).get();
            Elements novelMaster = chapterNameDocument.getElementsByTag("meta");
            //获取小说信息的母版
            Novel novel = new Novel().setScore("8.5")
                    .setName(novelMaster.get(12).attr("content"))
                    .setNovelName(novelMaster.get(8).attr("content"))
                    .setBriefIntroduction(novelMaster.get(9).attr("content"));
            String type = novelMaster.get(11).attr("content");
            //获取type类型信息
            if (("玄幻奇幻").equals(type)) {
                novel.setType(NovelStartEnum.FANTASY.ordinal());
            } else if (("武侠修真").equals(type)) {
                novel.setType(NovelStartEnum.FIXTHETRUTH.ordinal());
            } else if (("都市言情").equals(type)) {
                novel.setType(NovelStartEnum.METROPOLIS.ordinal());
            } else if (("网游竞技").equals(type)) {
                novel.setType(NovelStartEnum.ONLINE.ordinal());
            } else if (("科幻小说").equals(type)) {
                novel.setType(NovelStartEnum.SCIENECFICTION.ordinal());
            } else {
                novel.setType(NovelStartEnum.OTHER.ordinal());
            }
            for (Novel novel1 : selNovel) {
                if (novel1.getNovelName().equals(novelMaster.get(8).attr("content"))) {
                    novel = novel1;
                }
            }
            novels.add(novel);
        }
        return novels;
    }
}
